﻿using System;
using System.Collections.Generic;
using Savage.DotNetLibrary.DatabaseLibrary;
using System.Data;
using System.Data.SqlClient;

namespace Savage.SecureData
{
    public class Factory
    {
        public Factory(String connectionString)
        { 
            _databaseManager = new DatabaseManager(connectionString);
            _dataAccess = new DataAccess(connectionString);
        }

        DotNetLibrary.DatabaseLibrary.DatabaseManager _databaseManager;
        DataAccess _dataAccess;

        public void Save(Securable securable)
        {
            //See if a schema has been defined
            System.Xml.Schema.XmlSchemaSet xss = new System.Xml.Schema.XmlSchemaSet();
            
            foreach (Securable s in FindXQuery(securable.SchemaName, DocumentType.Xsd, null))
            { 
                //Check Data is valid against the schema
                System.Xml.XmlReader reader = System.Xml.XmlReader.Create(new System.IO.StringReader(s.Data.ToString()));
                System.Xml.Schema.XmlSchema schema = System.Xml.Schema.XmlSchema.Read(reader, ValidationHandler);
                xss.Add(schema);
            }
            if (xss.Count > 0)
            {
                System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings();
                settings.Schemas.Add(xss);
                settings.ValidationType = System.Xml.ValidationType.Schema;
                settings.ValidationEventHandler += (ValidationHandler);

                System.Xml.XmlReader vr = System.Xml.XmlReader.Create(new System.IO.StringReader(securable.Data.ToString()), settings);
                
                while (vr.Read()) ;
            }

            _dataAccess.Save(securable);
        }

        public static void ValidationHandler(object sender,
                                         System.Xml.Schema.ValidationEventArgs args)
        {
            throw new Exception(args.Message);
        }

        public IEnumerable<Securable> FindXQuery(string schemaName, DocumentType documentType, string xquery)
        {
            List<Securable> result = new List<Securable>();
            using (IDataReader reader = _dataAccess.FindXQuery(schemaName, documentType, xquery))
            {
                while (reader.Read())
                {
                    result.Add(new Securable(reader));
                }
            }
            return result;
        }

        public IEnumerable<Securable> FindText(string schemaName, string text)
        {
            List<Securable> result = new List<Securable>();
            using (IDataReader reader = _dataAccess.FindText(schemaName, text))
            {
                while (reader.Read())
                {
                    result.Add(new Securable(reader));
                }
            }
            return result;
        }

        public Securable Get(Guid securableId)
        {
            using (IDataReader reader = _dataAccess.Get(securableId))
            {
                if (reader.Read())
                    return new Securable(reader);
            }
            return null;
        }

        public void CreateRole(string roleName)
        {
            _databaseManager.Roles.CreateRole(roleName);
        }

        public void DropRole(string roleName)
        {
            _databaseManager.Roles.DropRole(roleName);
        }

        public string[] ListRoles()
        {
            return _databaseManager.Roles.ListRoles();
        }

        public System.Net.NetworkCredential CreateLoginForUser(string login)
        {
            //Generate a secure password
            string password = Savage.DotNetLibrary.ProtocolLibrary.SecurityWrapper.GenerateStrongPassword(40, 64);

            //Before the login is created the database name needs to be found
            SqlConnection connection = new SqlConnection(_databaseManager.ConnectionString);
            _databaseManager.Logins.CreateLogin(login, password, false, connection.Database);

            //Now create the user in the secure_data database
            _databaseManager.Users.CreateUser(login);

            return new System.Net.NetworkCredential(login, password);
        }
    }
}
